package com.example.demo.test;

import com.example.demo.api.account.OauthApi;
import com.example.demo.bean.Item;
import com.example.demo.bean.OauthTestInfo;
import com.example.demo.bean.PageFlow;
import com.example.demo.bean.User;
import com.example.demo.bean.conts.Oauth;
import com.example.demo.bean.entity.TFlow;
import com.example.demo.bean.entity.TTest;
import com.example.demo.repository.OauthService;
import com.example.demo.socket.WebSocketServer;
import com.example.demo.test.selenium.SeleniumAction;
import com.example.demo.util.BASE64;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Component
public class OauthAutoTestImpl extends SeleniumAction implements OauthTest {
    @Autowired
    private OauthService oauthService;
    @Autowired
    OauthApi oauthApi;
    private OauthTestInfo oauthInfo;
    private String email;
    private String password;
    private String code;
    private String token;

    @Override
    public void process(TTest info) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        List<OauthTestInfo> infoList = oauthService.oauthInfo("pro");
        Gson gson = new Gson();

        List<Item> item = gson.fromJson(gson.toJson(info.getItemList()), new TypeToken<List<Item>>() {
        }.getType());
        List<Integer> collect = item.stream().map(x -> Integer.parseInt(x.getId())).collect(Collectors.toList());

        List<OauthTestInfo> oauthTestInfos = infoList.stream().filter(x -> collect.contains(x.getId())).collect(Collectors.toList());

        List<User> userList = gson.fromJson(gson.toJson(info.getUserList()), new TypeToken<List<User>>() {
        }.getType());

        WebSocketServer.screenWarnMsg("测试开始 items: %s  users:%s ", oauthTestInfos.size(), userList.size());
        List<String> errors = new ArrayList<>();
        for (User user : userList) {
            this.email = user.getUsername();
            this.password = user.getPassword();
            for (int i = 0; i < oauthTestInfos.size(); i++) {
                WebSocketServer.screenInfoMsg("当前: %s   [总 : %s |  失败 %s]", i + 1, infoList.size(), errors.size());
                this.oauthInfo = oauthTestInfos.get(i);
                try {
                    loginByPassword();

                    getToken();

                    getProfile();

                    WebSocketServer.reportMsg("success", email, oauthInfo.getName());
                } catch (Exception e) {
                    e.printStackTrace();
                    WebSocketServer.screenErrorMsg("错误信息“ %s", e.getMessage());
                    errors.add(oauthInfo.getName());
                    WebSocketServer.reportMsg("error", email, oauthInfo.getName());
                } finally {
                    if (i < oauthTestInfos.size()) {
                        newInstance();
                    }
                }
            }
        }


        stopWatch.stop();
        WebSocketServer.screenInfoMsg("测试结束 耗时：%s 秒", stopWatch.getTotalTimeSeconds());
    }


    @Override
    public void loginByPassword() {
        WebSocketServer.screenInfoMsg("开始模拟登录");
        String loginurl = Oauth.getURLByEnv(oauthInfo.getEnv()) + "/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code&scope=read&state=1515";
        String loginUrl = String.format(loginurl, oauthInfo.getName(), oauthInfo.getWebServerRedirectUri());
        WebSocketServer.screenInfoMsg("打开URL : %s%n", loginUrl);
        driver.manage().deleteAllCookies();
        driver.get(loginUrl);
        driver.manage().window().setSize(new Dimension(1050, 660));
        driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
        boolean isautoapprove = Boolean.parseBoolean(oauthInfo.getAutoapprove());
        WebSocketServer.screenInfoMsg("是否自动授权 : %s", isautoapprove);
        if ("maestro".equalsIgnoreCase(oauthInfo.getClientLoginStyle())) {
            maestroForm();
            if (!isautoapprove) {
                WebSocketServer.screenInfoMsg("手动授权");
                String AUTHORIZE = "/html/body/div/main/center/div[1]/div[3]/div/form/div/div[2]/button";
                driver.findElement(By.xpath(AUTHORIZE)).click();
            }
        }
        if ("vtex".equalsIgnoreCase(oauthInfo.getClientLoginStyle())) {
            vtexForm();
            if (!isautoapprove) {
                WebSocketServer.screenInfoMsg("手动授权");
                String AUTHORIZE = "/html/body/div/main/center/div/div/div/form/div/div[2]/button";
                driver.findElement(By.xpath(AUTHORIZE)).click();
            }
        }
        this.code = null;


        wait.until((ExpectedCondition<Boolean>) driver -> driver.getCurrentUrl().contains("="));
        String currentUrl = driver.getCurrentUrl();

        if (currentUrl.indexOf("=") > 0) {
            this.code = currentUrl.substring(currentUrl.indexOf("=") + 1, currentUrl.indexOf("&"));
        }
        WebSocketServer.screenInfoMsg("获取当前页面地址 : %s ,   Code: %s ", currentUrl, code);

    }


    private void maestroForm() {
        driver.findElement(By.id("email")).click();
        driver.findElement(By.id("EamilAddress")).sendKeys(email);

        driver.findElement(By.id("pwd")).click();
        driver.findElement(By.id("password")).sendKeys(password);

        driver.findElement(By.id("login-submit")).click();
        WebSocketServer.screenInfoMsg("表单提交 : username: %s ,password: %s ", email, password);
    }

    private void vtexForm() {
        driver.findElement(By.id("username")).sendKeys(email);

        driver.findElement(By.id("password")).sendKeys(password);

        driver.findElement(By.id("login-submit")).click();
        WebSocketServer.screenInfoMsg("表单提交 : username: %s ,password: %s ", email, password);
    }

    @Override
    public void getToken() {
        WebSocketServer .screenInfoMsg("获取Token信息");
        String authorization = "Basic " + BASE64.encrypt(oauthInfo.getName() + ":" + oauthInfo.getClientSecret());
        Map<String, String> map = new HashMap<>();
        map.put("grant_type", "authorization_code");
        map.put("scope", "read");
        map.put("redirect_uri", oauthInfo.getWebServerRedirectUri());
        map.put("code", code);
        WebSocketServer.screenInfoMsg("getToken authorization: " + authorization + " " + oauthInfo.getWebServerRedirectUri() + "  " + code);
        String token = oauthApi.token(authorization, map);
        WebSocketServer.screenInfoMsg("getToken 返回: " + token);
        JsonObject jsonObject = new Gson().fromJson(token, JsonObject.class);
        this.token = jsonObject.get("access_token").getAsString();
    }

    @Override
    public void getProfile() {
        WebSocketServer.screenInfoMsg("获取用户信息");
        String authorization = "Bearer " + token;
        String body = "";
        if (oauthInfo.getClientIsSmb() == 1) {
            WebSocketServer.screenInfoMsg("获取SMB用户信息..");
            body = oauthApi.publicBaseProfile(authorization);
        } else if ("vtex".equalsIgnoreCase(oauthInfo.getClientLoginStyle())) {
            WebSocketServer.screenInfoMsg("获取vtex用户信息..");
            body = oauthApi.vtexBseProfile(authorization);
        } else {
            WebSocketServer.screenInfoMsg("获取基本用户信息..");
            body = oauthApi.bseProfile(authorization);
        }
        WebSocketServer.screenInfoMsg(body);
    }

    @Override
    public TFlow getFlowChart() {
        //List<String> list = Arrays.asList("lightblue", "pink", "orange", "lightgreen");

        TFlow tFlow = new TFlow();
        PageFlow pageFlow = new PageFlow();
        List<PageFlow.NodeData> nodeDataArrayList = new ArrayList<>();
        nodeDataArrayList.add(new PageFlow.NodeData(0, "user", null, "lightblue", null));
        nodeDataArrayList.add(new PageFlow.NodeData(1, "loginByPassword", null, "orange", null));
        nodeDataArrayList.add(new PageFlow.NodeData(2, "getToken", null, "orange", null));
        nodeDataArrayList.add(new PageFlow.NodeData(3, "getPublicProfile", null, "orange", null));
        nodeDataArrayList.add(new PageFlow.NodeData(4, "success", null, "lightgreen", null));
        pageFlow.setNodeDataArray(nodeDataArrayList);

        List<PageFlow.LinkData> linkDataArray = new ArrayList<>();
        linkDataArray.add(new PageFlow.LinkData(0, 1));
        linkDataArray.add(new PageFlow.LinkData(1, 2));
        linkDataArray.add(new PageFlow.LinkData(2, 3));
        linkDataArray.add(new PageFlow.LinkData(3, 4));
        pageFlow.setLinkDataArray(linkDataArray);
        tFlow.setId(1);
        tFlow.setFlow(pageFlow);
        tFlow.setTitle("Oauth基本登录流程测试");
        tFlow.setDescription("基本登录流程测试");
        tFlow.setType("oauthAutoTestImpl");
        return tFlow;
    }
}
